﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters;
using System.Collections;
using System.Threading;

using dHash;

namespace dHash_Client
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Threading.Thread.Sleep(2000);
            //wait for server.
            BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
            provider.TypeFilterLevel = TypeFilterLevel.Full;

            IDictionary props = new Hashtable();
            props["port"] = 0;

            Console.WriteLine("Starting listening channel...");
            TcpChannel chan = new TcpChannel(props, null, provider);

            ChannelServices.RegisterChannel(chan, true);

            // Create the object for calling into the server
            dashServer server = (dashServer)
                Activator.GetObject(typeof(dashServer),
                "tcp://127.0.0.1:5566/dHash");		//  Must match IP and port on server

            // Define sink for events
            RemotingConfiguration.RegisterWellKnownServiceType(
                typeof(clientCallBack),
                "dashClient",
                WellKnownObjectMode.Singleton);

            //client c = new client();
            server.connect(new client());


            while (true)
            {
                System.Threading.Thread.Sleep(1000);
                //server.connect(new client());
            }
           
        }
    }

    

    public class client : clientCallBack
    {
        class threadmanager
        {
            jobthread current = null;
            jobdetails currentdetails;
            client c = null;
            
            public threadmanager(client client)
            {
                c = client;
            }

            public void executejob()
            {
                if (current == null)
                {
                    lock (c.jobs)
                    {
                        if (c.jobs.Count > 0)
                        {
                            currentdetails = c.jobs[0];
                            c.jobs.Remove(currentdetails);
                            current = new jobthread(currentdetails, this);
                            Thread t = new Thread(new ThreadStart(current.startjob));
                            t.Priority = ThreadPriority.Lowest;
                            t.Start();
                            Console.WriteLine("started new job....");
                        }
                    }

                }
            
            }

            public void killjob(int taskhash)
            {
                current.killjob(taskhash);
            }

            public void jobcomplete()
            {
                current = null;
                executejob();

            }

        }

        class jobthread
        {
            bool complete = false;
            jobdetails details;
            threadmanager mgr;
            hashfunc func;
            public jobthread(jobdetails job,threadmanager manager)
            {
                details = job;
                mgr = manager;
                func = hash.getfunc(job.func);
            }

            public void startjob()
            {
                genPass(details.prefix, details.lentogo);
                mgr.jobcomplete();
            }

            public void killjob(int taskhash)
            {
                if (taskhash == details.taskhash)
                {
                    complete = true;
                }
            }

            void genPass(string prefix, int len)
            {
                if (complete)
                    return;
                if (len == 0)
                {
                    if (details.targethash.Equals(func(prefix, details.salt)))
                    {
                        complete = true;
                        //notify server
                        return;
                    }
                    
                }
                else
                {
                    len--;
                    foreach (char c in details.charset)
                    {
                        genPass(prefix + c, len);
                    }

                }
            }
        }

        List<jobdetails> jobs = new List<jobdetails>();
        threadmanager mgr;
       

        public client()
        {
            mgr = new threadmanager(this);
        }

        public override void canceljob(int taskhash)
        {
            List<jobdetails> temp = new List<jobdetails>();
            Console.WriteLine("removing jobs...");
            lock (jobs)
            {
                foreach (jobdetails job in jobs)
                {
                    if (job.taskhash == taskhash)
                    {
                        temp.Add(job);
                    }
                }

                foreach (jobdetails job in temp)
                {
                    jobs.Remove(job);
                }
            }
            mgr.killjob(taskhash);

        }
        

        public override void addjob(jobdetails job)
        {
            Console.WriteLine("added new job...");
            lock (jobs)
            {
                jobs.Add(job);
            }
            mgr.executejob();
            
        }
       
    }
}
